var LoginView = function(){
	var thisView = this;
	
	this.schemeSelect = $("#scheme");
	this.environmentSelect = $("#environment");
	this.loginForm = $("#login");
	this.username = this.loginForm.find('input[name="user"]');
	this.password = this.loginForm.find('input[name="password"]');
	this.loginButton = this.loginForm.find('input[type="submit"]');
	this.loginConsumerLabel = this.loginForm.find('#labelConsumerKeys');
	this.loginAccessLabel = this.loginForm.find('#labelAccessKeys');
	this.loggedInForm = $("#loggedIn");
	this.newRequestLink = $("#newRequestLink");
	this.newRequestInput = this.loggedInForm.find('input[type="hidden"]');
	
	this.setEnvironments = function(environmentsArray){
		thisView.environmentSelect.empty();
		for(var i = 0; i < environmentsArray.length; i++){
			thisView.environmentSelect.append('<option value="'+ i + '">' + environmentsArray[i] +'</option>');
		};
		if(thisView._selectedEnv){
			thisView.environmentSelect.val(thisView._selectedEnv);
		}else{
			thisView.onEnvSelectChange();
		}
	};
	
	this.environmentSelect.change(function(){
		thisView.onEnvSelectChange();
	});
	
	this.loginForm.submit(function(){
		
		if(isLoginMode()){
		
			if(thisView.username.val() && thisView.password.val()){
				thisView.onLogin();
			}
			else{
				alert("Username or password empty!");
				if(thisView.username.val() != "" && thisView.password.val() == ""){
					thisView.password.focus();
				}
				else{
					thisView.username.focus();
				}
			}
		}
		else{
			thisView.onLogOut();
		}
		return false;
	});
		
	this.newRequestLink.click(function() {
		thisView.onNewRequest();
		return false; 
	});
	
	this.setLoggedIn = function(user){
		thisView.loginButton.attr("value", 'Logout');
		thisView.loginButton.attr("disabled", false);
		setLoginAccessText("Access keys: [" + user.accessKey + ", " + user.accessSecret + "]");
		thisView.newRequestLink.show();
	};
	
	this.setPreviouslyLoggedIn = function(username, selectedEnv, accessKeys, scheme, consumer){
		thisView.username.val(username);
		thisView._selectedEnv = selectedEnv;
		thisView.setSelectedScheme(scheme);
		setInputsEnabled(false);
		thisView.setConsumerKeys(consumer);
		thisView.setLoggedIn(accessKeys);
	};
	
	this.setLoggedOut = function(){
		thisView.password.attr("value", "");
		thisView.loginButton.attr("value", 'Login');
		setInputsEnabled(true);
		setLoginAccessText("");
		thisView.username.focus();
		thisView.newRequestLink.hide();
	};
	
	this.newRequest = function(user){
		thisView.newRequestInput.val(user);
		thisView.loggedInForm.submit();
	};
	
	this.onLogin = new Subscribable(function(){
		setInputsEnabled(false);
		thisView.loginButton.attr("value", 'sending...');
		
		var username = thisView.username.get(0).value;
		var password = thisView.password.get(0).value;
		var selectedEnv = thisView.environmentSelect.get(0).selectedIndex;
		var scheme = thisView.schemeSelect.val();
		return {'username': username, 'password': password, 'environment':selectedEnv, 'scheme': scheme};
	});
	
	this.onLogginError = function(status, response) {
		alert("HTTP " + status + " - " + response);
		thisView.onLogOut();
	};
	
	this.onLogOut = new Subscribable(function(){
		thisView.setLoggedOut();
	});
	
	this.onNewRequest = new Subscribable(function(){
		var username = thisView.username.get(0).value;
		var selectedEnv = thisView.environmentSelect.get(0).selectedIndex;
		return {'username': username, 'selectedEnv':selectedEnv};
	});
	
	this.onEnvSelectChange = new Subscribable(function(){
		var selectedEnv = thisView.environmentSelect.get(0).selectedIndex;
		return selectedEnv;
	});
	
	this.setSelectedScheme = function(scheme){
		thisView.schemeSelect.val(scheme);
	};
	
	this.setConsumerKeys = function(consumer){
		setLoginConsumerText("Consumer keys: [" + consumer.key + ", " + consumer.secret + "]");
	};
	
	var setInputsEnabled = function(value){
		thisView.loginButton.attr("disabled", !value);
		thisView.environmentSelect.attr("disabled", !value);
		thisView.schemeSelect.attr("disabled", !value);
		thisView.username.attr("disabled", !value);
		thisView.password.attr("disabled", !value);
	};
	
	var setLoginAccessText = function(text){
		thisView.loginAccessLabel.empty();
		thisView.loginAccessLabel.append(text);
	};
	
	var setLoginConsumerText = function(text){
		thisView.loginConsumerLabel.empty();
		thisView.loginConsumerLabel.append(text);
	};
	
	var isLoginMode = function(){
		return (thisView.loginButton.attr("value") == "Login");
	};
};
//-------------------------------------------------------------------------------------------------------------------------------

var ApiServiceView = function(){
	var thisView = this;
	
	this.apiServiceForm = $("#apiService");
	this.apiSelect = $("#api");
	this.serviceSelect = $("#service");
	this.serviceFilter = $("#serviceFilter");
	this.servicesCount = $("#servicesCount");
	this.apiServiceButton = this.apiServiceForm.find('input[type="submit"]');
	this.apiVersionDiv = $("#versionDiv");
	
	this.SERVICE_SELECT_LABEL = "-- Select a service --";
	this.SERVICES_NOT_FOUND_LABEL = "-- No services found --";
	
	this.enable = function(value){
		thisView.apiSelect.attr("disabled", !value);
		thisView.serviceSelect.attr("disabled", !value);
		thisView.apiServiceButton.attr("disabled", !value);
		thisView.serviceFilter.attr("disabled", !value);
		
		if(value){
			thisView.serviceFilter.focus();
		}
	};
	
	this.setApis = function(apisArray){
		thisView.apiSelect.empty();
		for(var i = 0; i < apisArray.length; i++){
			thisView.apiSelect.append('<option value="'+ i + '">' + apisArray[i] +'</option>');
		};
	};
	
	this.setServices = function(servicesArray){
		thisView._servicesArray = servicesArray;
		showFilteredServices();
	};
	
	this.apiSelect.change(function(){
		thisView.onApiSelected();
	});
	
	this.serviceSelect.change(function(){
		thisView.onServiceSelected();
	});
	
	this.serviceSelect.keyup(function(keyEvent){
		var KEY_RETURN_CODE = 13;
		if(keyEvent.keyCode == KEY_RETURN_CODE){
			thisView.onServiceSelected();
		}
	});
	
	this.onApiSelected = new Subscribable(function(){
		thisView.serviceFilter.val("");
		thisView.serviceFilter.focus();
		return thisView.apiSelect.get(0).selectedIndex;
	});
	
	this.onServiceSelected = new Subscribable(function(){
		thisView.serviceSelect.attr("size", "1");
		var serviceSelect = thisView.serviceSelect.get(0);
		if(serviceSelect.options[0].label == thisView.SERVICE_SELECT_LABEL){
			serviceSelect.remove(0);
		}
		
		var apiIndex = thisView.apiSelect.get(0).selectedIndex;
		var serviceOption = serviceSelect.options[serviceSelect.selectedIndex];
		return {'apiIndex': apiIndex, 'serviceIndex': serviceOption.value};
	});
	
	this.setApiVersion = function(apiVersion){
		if(apiVersion != ""){
			thisView.apiVersionDiv.append("version api: " + apiVersion);
		}
	};
	
	this.isServiceSelected = function(){
		var serviceSelect = thisView.serviceSelect.get(0);
		return (serviceSelect.options[0].label != thisView.SERVICE_SELECT_LABEL && serviceSelect.options[0].label != thisView.SERVICES_NOT_FOUND_LABEL);
	};
    
    var showFirstOptions = function(countLimit){
    	var select = thisView.serviceSelect;
		var optionsCount = select.get(0).options.length;
		var optionsArray = thisView._servicesArray;
		
		thisView.servicesCount.empty();
		thisView.servicesCount.append(optionsCount);
        if(optionsCount != optionsArray.length){
        	thisView.servicesCount.append(" of " + optionsArray.length);	
        }
	
		if(optionsCount > 0 ){
			if(optionsCount <= countLimit){
				select.attr("size", optionsCount);
			}
			else{
				thisView.serviceSelect.prepend('<option value="-1">' + thisView.SERVICE_SELECT_LABEL + '</option>');
				select.attr("size", "1");
			}
		}
		else{
			thisView.serviceSelect.append('<option value="-1">' + thisView.SERVICES_NOT_FOUND_LABEL + '</option>');
			select.attr("size", "1");
		}
    };
	
    var showFilteredServices = function(){
    	var textFilter = thisView.serviceFilter.val();
		var select = thisView.serviceSelect;
		var optionsArray = thisView._servicesArray;
		select.empty();
		
		for(var i = 0; i < optionsArray.length; i++){
            var option = optionsArray[i];
            if(option.toLowerCase().indexOf(textFilter.toLowerCase()) >= 0){
                select.append('<option value="' + i + '">' + option + '</option>');
            }    
        }
        showFirstOptions(10);
    };
    
	this.serviceFilter.keyup(function(){
		 showFilteredServices();
    });
	
	this.serviceFilter.click(function() {
		thisView.serviceFilter.select();
    });
	
	this.serviceFilter.keydown(function(keyEvent){
		var KEY_ARROW_DOWN = 40;
		var KEY_RETURN_CODE = 13;
		if(keyEvent.keyCode == KEY_ARROW_DOWN){
			thisView.serviceSelect.focus();
		}
		else if(keyEvent.keyCode == KEY_RETURN_CODE){ 
			var serviceSelect = thisView.serviceSelect.get(0);
			if(serviceSelect.selectedIndex == -1){
				serviceSelect.selectedIndex = 0;
			}
			if(thisView.isServiceSelected()){
				thisView.onServiceSelected();
			}
		}
	});
};
//------------------------------------------------------------------------------------------------------
var RequestView = function(){
	var thisView = this;

	this.SELECT_OPTION_LABEL = "Select option";
	this.SELECT_ENUM_LABEL = "Select enum option";
	
	this.requestForm = $("#request");
	this.requestLabel = this.requestForm.find('label');
	this.fieldsDiv = $("#fields");
	this.requestButton = this.requestForm.find('input[type="submit"]');
	
	this.requestInput = this.requestForm.find('input[type="hidden"]');
	this.iterationsCheck = this.requestForm.find("#iterationCheck");
	this.iterationFrom = this.requestForm.find("#iterationFrom");
	this.iterationTo = this.requestForm.find("#iterationTo");
	
	this.javadocLink = $("#javadocLink");
	
	this.enable = function(value){
		if(value){
			var objFocus = thisView.requestButton;
			var fieldFocus = null;
			for(var name in thisView._fields){
				var fieldObj = thisView._fields[name].input;
				if(!fieldObj.attr("disabled") && !fieldObj.val() && !fieldFocus){
						fieldFocus = fieldObj;
				}
			}
			if(fieldFocus){
				objFocus = fieldFocus;
			}
			thisView.requestForm.show();
			objFocus.focus();
		}
		else{
			thisView.requestForm.hide();
		}
	};
	
	this.setLabel = function(service){
		var deprecatedMsg = "";
		if(service.deprecated){
			deprecatedMsg = "(DEPRECATED)  ";
		}
		thisView.requestLabel.text(deprecatedMsg + service.verb + "  " + service.path);
	};
	
	this.setFields = function(fieldsArray){
		thisView.fieldsDiv.empty();
		thisView._fields = new Object();
		for(var i = 0; i < fieldsArray.length; i++){
			var name = fieldsArray[i].name;
			if(!thisView._fields[name]){
				var type = "text";
				if(fieldsArray[i].isFile){
					type = "file";
				}
				thisView.fieldsDiv.append('<tr id="'+ name + 'Field"><td name="typeCell">  </td><td name="nameCell" align="center">' + name +'</td><td name="inputCell">: </td><td name="nullCell"></td><td name="selectCell">  </td></tr>');
				var field = new Object();
				field.name = name;
				field.div = thisView.fieldsDiv.find('#' + name + 'Field');
				
				var inputCell = field.div.find('td[name="inputCell"]');
				inputCell.append('<input type="' + type + '" size="60" id="' + name + '"/>');
				
				field.input = thisView.fieldsDiv.find('input[id="' + name + '"]');
				if(name == "length"){
					name = "_length";
				}
				thisView._fields[name] = field;
	
				setNullCheckbox(name, field);
			}
		};
		setIterations(false);
	};
	
	var setNullCheckbox = function(name, field){
		var nullCell = field.div.find('td[name="nullCell"]');
		nullCell.append(' <input type="checkbox" id="' + name + 'Checkbox" value="null" tabindex="1000"/> null');
		
		field.checkbox = field.div.find('input[id="' + name + 'Checkbox"]');
		field.checkbox.change(function(){
			var checked = (this.checked);
			thisView.setFieldNull(checked, this.name);
		});
		field.checkbox.attr("name", name);
	};
	
	var getField = function(name){
		var fieldName = name;
		if(name == "length"){
			fieldName = "_length";
		};
		return thisView._fields[fieldName];
	};
	
	this.setFieldNull = function(value, fieldName){
		var field = getField(fieldName);
		if(value){
			field.input.attr("value", "");
			if(field.defaultValue){
				field.input.val(field.defaultValue);
				setDefaultSelectedValue(field);
			}
			
			field.input.attr("disabled", true);
			field.checkbox.attr("checked", "checked");
			if(field.select){
				field.select.attr("disabled", true);
			}
		}
		else{
			field.input.attr("disabled", false);
			field.checkbox.removeAttr("checked");
			if(field.select){
				field.select.attr("disabled", false);
			}
			field.input.focus();
		}
	};
	
	var setDefaultSelectedValue = function(field){
		if(field.select){
			var select = field.select.get(0);
			var defaultValue = field.defaultValue;
			for(var i = 0; i < select.options.length; i++){
				if(select.options[i].value == defaultValue){
					select.selectedIndex = i;
					if(select.options[0].label == thisView.SELECT_OPTION_LABEL || select.options[0].label == thisView.SELECT_ENUM_LABEL){
						select.remove(0);
					}
					return true;
				}
			}
		}
	};
	
	this.setEnumValues = function(name, values){
		addEnumSelect(name, values);
		var field = getField(name);
		field.select.change(function(){
			var id = this.value;
			thisView.enumSelectChange(id, this.name);
		});
	};
	
	this.setOptionValues = function(name, values){
		addOptionSelect(name, values);
		var field = getField(name);
		field.select.change(function(){
			thisView.optionSelectChange(this.value, this.name);
		});
	};
	
	var addEnumSelect = function(name, values){
		var field = getField(name);
		var selectCell = field.div.find('td[name="selectCell"]');
		selectCell.append('  <select id="' + field.name + 'Select"></select>');
		field.select = field.div.find('#' + field.name + 'Select');
		var select = field.select.get(0);
		select.options[0] = new Option(thisView.SELECT_ENUM_LABEL, -1);
		for(var j = 0; j < values.length; j++){
			select.options[j + 1] = new Option(values[j].name, values[j].id);
		}
		field.select.attr("name", field.name);
	};
	
	var addOptionSelect = function(name, values){
		var field = getField(name);
		var selectCell = field.div.find('td[name="selectCell"]');
		selectCell.append('  <select id="' + field.name + 'Select"></select>');
		field.select = field.div.find('#' + field.name + 'Select');
		var select = field.select.get(0);
		select.options[0] = new Option(thisView.SELECT_OPTION_LABEL, -1);
		for(var j = 0; j < values.length; j++){
			select.options[j + 1] = new Option(values[j], values[j]);
		}
		field.select.attr("name", field.name);
	};
	
	this.setListEnumValues = function(name, values){
		addEnumSelect(name, values);
		var field = getField(name);
		field.select.change(function(){
			var id = this.value;
			thisView.listEnumSelectChange(id, this.name);
		});
	};
	
	this.setDefaultValue = function(name, defaultValue){
		var field = getField(name);
		field.defaultValue = defaultValue;
		field.input.val(defaultValue);
	};
	
	this.setFieldType = function(name, type){
		var field = getField(name);
		var typeCell = field.div.find('td[name="typeCell"]');
		typeCell.empty();
		typeCell.append('<b>' + type + '</b>');
	};
	
	this.setFieldValue = function(name, value){
		var field = getField(name);
		if(field){
			field.input.val(value);
			thisView.setFieldNull(false, name);
		}
	};
	
	this.optionSelectChange = function(option, name){
		var field = getField(name);
		field.input.val(option);
		var select = field.select.get(0);
		if(select.options[0].label == thisView.SELECT_OPTION_LABEL){
			select.remove(0);
		}
	};
	
	this.enumSelectChange = function(id, name){
		var field = getField(name);
		field.input.val(id);
		var select = field.select.get(0);
		if(select.options[0].label == thisView.SELECT_OPTION_LABEL){
			select.remove(0);
		}
	};
	
	this.listEnumSelectChange = function(id, fieldName){
		var field = getField(fieldName);
		var value = field.input.val();
		value += "," + id;
		if(value.charAt(0) == ','){
			value = value.substring(1, value.length);
		}
		field.input.val(value);
	};
	
	this.setFileEvents = function(name){
		var field = getField(name);
		field.input.change(function(){
			var file = this.files[0];
			thisView.setFieldValue("_length", file.size);
			thisView.setFieldValue("fileName", file.name);
		});
	};
	
	this.setMultipartRequest = function(value){
		thisView.iterationsCheck.attr("disabled", value);
	};
	
	this.setMultipart = function(path, formParams){
		thisView.requestForm.attr("enctype", "multipart/form-data");
		thisView.requestForm.attr("action", path);
		
		thisView.requestInput.removeAttr("name");
		thisView.requestInput.removeAttr("value");
		
		for(fieldName in thisView._fields){
			var field = thisView._fields[fieldName];
			var name = fieldName;
			if(fieldName.substring(0,1) == "_"){
				name = fieldName.substring(1);
			}
			if(!formParams[name]){
				field.input.removeAttr("name");
			}
			else if(field.checkbox.attr("checked")){
				thisView.setFieldNull(false, fieldName);
				field.input.attr("value", "");
			}
			else{
				field.input.attr("name", name);
			}
		}
	};
	
	this.setNormalRequest = function(requestData){
		thisView.requestForm.removeAttr("enctype");
		thisView.requestForm.attr("action", "response.jsp");
		thisView.requestInput.attr("name", "_request");
		thisView.requestInput.attr("value", requestData);
	};
	
	this.requestForm.submit(function(){
		if(!verifyIterations()){
			return false;
		}
		thisView.onSendRequest();
	});
	
	this.onSendRequest = new Subscribable(function(){
		var parameters = {};
		for(fieldName in thisView._fields){
			var field = thisView._fields[fieldName];
			if(!field.checkbox.attr("checked")){
				field.input.attr("name", field.name);
				parameters[fieldName] = field.input.val();
			}
		}
		var iterations = null;
		if(thisView.iterationsCheck.attr("checked")){
			iterations = {};
			iterations.from = thisView.iterationFrom.val();
			iterations.to = thisView.iterationTo.val();
		}
		sendParams = {};
		sendParams.parameters = parameters;
		sendParams.iterations = iterations;
		return sendParams;
	});
	
	this.iterationsCheck.change(function(){
		var checked = (this.checked);
		setIterations(checked);
	});
	
	var setIterations = function(value){
		if(value){
			thisView.iterationsCheck.attr("checked", "checked");
			thisView.iterationFrom.attr("disabled", false);
			thisView.iterationTo.attr("disabled", false);
		}
		else{
			thisView.iterationsCheck.removeAttr("checked");
			thisView.iterationFrom.attr("disabled", true);
			thisView.iterationTo.attr("disabled", true);
			thisView.iterationFrom.val("0");
			thisView.iterationTo.val("1");
		}
	};
	
	this.iterationFrom.change(function(){
		checkNumber(thisView.iterationFrom);
	});
	
	this.iterationTo.change(function(){
		checkNumber(thisView.iterationTo);
	});
	
	var checkNumber = function(input){
		var n = input.val();
		if(!isNumber(n)){
			alert("Invalid number");
			input.val("");
			input.focus();
		}
	};
	
	var isNumber = function(number){
		return !isNaN(parseFloat(number)) && isFinite(number);
	};
	
	var verifyIterations = function(){
		var verified = true;
		var itFrom = thisView.iterationFrom.val();
		if(!isNumber(itFrom)){
			thisView.iterationFrom.focus();
			verified = false;
		}
		var itTo = thisView.iterationTo.val();
		if(!isNumber(itTo)){
			thisView.iterationTo.focus();
			verified = false;
		}
		if(itTo <= itFrom){
			alert("To must be bigger than From");
			thisView.iterationTo.focus();
			verified = false;
		}
		return verified;
	};
	
	this.setJavadocLink = function(linkPath){
		thisView.javadocLink.attr("href", linkPath);
	};
};
//-------------------------------------------------------------------------------------------------------------------------
var ResponseView = function(){
	var thisView = this;
	
	this.SENDING_TITLE_MESSAGE = "Api Client - Sending...";
	this.RESPONSE_TITLE_MESSAGE = "Api Client - ";
	this.SENDING_MESSAGE = "sending...";
	
	this.responseDiv = $("#response");
	this.responseArea = $("#responseArea");
	this.responseMsgDiv = $('#responseMsgDiv');
	this.serviceH = $("#serviceH");
	this.parametersLabel = $("#parametersLabel");
	this.body = $("body");
	
	this.doLoad = function(environment, service, user, parameters, iterations){
		thisView.serviceH.empty();
		thisView.serviceH.append(service.verb + ' ' + environment.scheme + "://" + environment.host + service.service + service.path);
		
		document.title = thisView.SENDING_TITLE_MESSAGE;
		
		if(iterations){
			var itNumber = iterations.from;
			thisView.responseMsgDiv.append('<label id="it' + itNumber + '">Iteration ' + iterations.from + ' of ' + iterations.to + ': ' + thisView.SENDING_MESSAGE + '</label><br>');
			thisView._currentIteration = thisView.responseMsgDiv.find("#it" + itNumber);
		}
		else{
			thisView.responseMsgDiv.append(thisView.SENDING_MESSAGE);
		}
		thisView.parametersLabel.empty();
		var jsonParams = JSON.stringify(parameters).replace("\n\r", "");
		if(jsonParams != "{}"){
			thisView.parametersLabel.append(jsonParams);
		}
	};
	
	this.setResponse = function(code, response, time, isHtml){
		document.title = thisView.RESPONSE_TITLE_MESSAGE + code;

		var statusCode = code + " " + time + "ms";
		if(thisView._currentIteration){		
			var log = thisView._currentIteration.text();
			log = log.substring(0, (log.length - thisView.SENDING_MESSAGE.length));
			thisView._currentIteration.empty();
			thisView._currentIteration.append(log + statusCode);
		}
		else{
			thisView.responseMsgDiv.empty();
			thisView.responseMsgDiv.append(statusCode);
		}
		thisView.responseArea.val(response);
		var textArea = thisView.responseArea.get(0);
		var hight = textArea.scrollHeight + 5;
		textArea.style.height = hight + 'px';
		if(isHtml){
			thisView.body.append("<br> HTML Preview: <br>");
			thisView.body.append(response);
		}
	};
};